/**
 * Copyright (c) 2020-2030 LiuBoTao [1211265557@qq.com]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.amos.server.modules.upms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.amos.core.basic.constant.SystemConstant;
import org.amos.core.basic.exception.ServiceException;
import org.amos.core.basic.utils.AmosUtils;
import org.amos.core.basic.utils.crud.WrapperBuilder;
import org.amos.core.frame.utils.IdUtils;
import org.amos.server.modules.upms.dto.RoleListDTO;
import org.amos.server.modules.upms.dto.RoleMenuDTO;
import org.amos.server.modules.upms.dto.RoleUserDTO;
import org.amos.server.modules.upms.dto.TenantRoleDTO;
import org.amos.server.modules.upms.entity.*;
import org.amos.server.modules.upms.mapper.RoleMapper;
import org.amos.server.modules.upms.service.IMenuService;
import org.amos.server.modules.upms.service.IRoleMenuService;
import org.amos.server.modules.upms.service.IRoleService;
import org.amos.server.modules.upms.service.IUserRoleService;
import org.amos.server.modules.upms.vo.RoleVO;
import org.amos.server.utils.SysTreeUtils;
import org.amos.tenant.annotation.TenantIgnore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static org.amos.core.basic.constant.SystemConstant.SYS_DELETE_FLAG_DEFAULT;
import static org.amos.core.basic.constant.SystemConstant.SYS_IS_ADMIN;

/**
 * 角色表 服务实现类
 *
 * @author CodeGenerator
 * @since 2020-12-20
 */
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
    @Autowired
    private IMenuService menuService;
    private final IRoleMenuService roleMenuService;
    @Autowired
    private IUserRoleService userRoleService;
    private final SysTreeUtils<Role> sysTreeUtils;


    @Override
    public Boolean saveOrUpdateRole(Role role) {
        long count = 0;
        if (Objects.nonNull(role.getId())) {
            count = baseMapper.count(new HashSet<>(Arrays.asList(role.getId())), SystemConstant.STS_TENANT_ADMIN_ROLE_ALIAS);
        }
        if (count > 0) {
            throw new ServiceException("租户管理员角色信息不能变更！");
        }
        super.saveOrUpdate(role);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveTenantRole(TenantRoleDTO dto) {
        // 保存角色信息
        Long roleId = IdUtils.nextId();
        Role role = new Role();
        role.setId(roleId);
        role.setTenantId(dto.getTenantId());
        role.setName(dto.getRoleName());
        role.setAlias(dto.getRoleCode());
        role.setSort(0);
        role.setStatus(SystemConstant.SYS_EFFECTIVE_STATUS);
        super.save(role);
        // 设置菜单权限
        RoleMenuDTO roleMenuDTO = new RoleMenuDTO();
        roleMenuDTO.setRoleId(roleId);
        roleMenuDTO.setPermissions(dto.getPermissions());
        this.resetRolePermission(roleMenuDTO);
        return roleId;
    }

    @Override
    @TenantIgnore
    public Boolean updateTenantRole(TenantRoleDTO dto) {
        // 设置菜单权限
        Set<Long> permissions = dto.getPermissions();
        String roleCode = dto.getRoleCode();
        QueryWrapper qw = new QueryWrapper();
        qw.eq(AmosUtils.toDbField(Role::getTenantId), dto.getTenantId());
        qw.eq(AmosUtils.toDbField(Role::getAlias), roleCode);
        qw.eq(AmosUtils.toDbField(Role::getIsDeleted), SYS_DELETE_FLAG_DEFAULT);
        Role role = super.getOne(qw);

        RoleMenuDTO roleMenuDTO = new RoleMenuDTO();
        roleMenuDTO.setRoleId(role.getId());
        roleMenuDTO.setPermissions(permissions);
        this.resetRolePermission(roleMenuDTO);
        return Boolean.TRUE;
    }

    @Override
    public Boolean remove(Set<Long> ids) {
        // 系统默认ID 数据不能删除
        boolean contains = CollUtil.contains(ids, SystemConstant.SYS_DEFAULT_ID);
        if (contains) {
            throw new ServiceException("系统内置数据不能变更！");
        }
        long count = baseMapper.count(ids, SystemConstant.STS_TENANT_ADMIN_ROLE_ALIAS);
        if (count > 0) {
            throw new ServiceException("租户管理员角色信息不能变更！");
        }

        UpdateWrapper<Role> uw = new UpdateWrapper<>();
        uw.in(AmosUtils.toDbField(Role::getId), ids)
        .set(AmosUtils.toDbField(Role::getIsDeleted), SystemConstant.SYS_DELETE_FLAG_ALREADY);
        super.update(uw);
        return Boolean.TRUE;
    }

    @Override
    public Set<String> getUserPermissions(User user) {
        Set<String> permissions = new HashSet<>();
        // 如果是管理员直接返回
        if (SYS_IS_ADMIN.equals(user.getIsAdmin())) {
            permissions.add("*");
            return permissions.stream().map(String::new)
                    .collect(Collectors.toSet());
        }

        List<Menu> userMenu = menuService.getUserMenu(user.getId(), SystemConstant.MENU_TYPE_PERMISSION);
        permissions = userMenu.stream().filter(menu -> StrUtil.isNotBlank(menu.getPermission())).map(Menu::getPermission).collect(Collectors.toSet());
        return permissions;
    }

    @Override
    public List<RoleVO> selectList(RoleListDTO dto) {
        QueryWrapper qw = new WrapperBuilder().build(dto);
        qw.eq(AmosUtils.toDbField(Role::getIsDeleted), SYS_DELETE_FLAG_DEFAULT);
        List<Role> roles = baseMapper.selectList(qw);
        if (CollUtil.isEmpty(roles)) {
            return new ArrayList<>();
        }
        List<RoleVO> voList = AmosUtils.listCopy(roles, RoleVO.class);
        return voList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetRolePermission(RoleMenuDTO dto) {
        Set<Long> permissionIds = dto.getPermissions();
        Long roleId = dto.getRoleId();

        // 校验更新角色是否租户管理员
        long count = baseMapper.count(new HashSet<>(Arrays.asList(roleId)), SystemConstant.STS_TENANT_ADMIN_ROLE_ALIAS);
        if (count > 0) {
            throw new ServiceException("租户管理员角色信息不能变更！");
        }

        UpdateWrapper<RoleMenu> uw = new UpdateWrapper<>();
        uw.eq(AmosUtils.toDbField(RoleMenu::getRoleId), roleId);
        roleMenuService.remove(uw);

        List<RoleMenu> roleMenus = new ArrayList<>();
        permissionIds.forEach(x -> {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(roleId);
            roleMenu.setMenuId(x);
            roleMenus.add(roleMenu);
        });
        roleMenuService.saveBatch(roleMenus);
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetRoleUser(RoleUserDTO dto) {
        Set<Long> userIds = dto.getIds();
        Set<Long> roles = dto.getRoles();

        UpdateWrapper<UserRole> uw = new UpdateWrapper<>();
        uw.in(AmosUtils.toDbField(UserRole::getUserId), userIds);
        userRoleService.remove(uw);

        List<UserRole> userRoles = new ArrayList<>();
        userIds.forEach(x -> {
            roles.forEach(r -> {
                UserRole userRole = new UserRole();
                userRole.setRoleId(r);
                userRole.setUserId(x);
                userRoles.add(userRole);
            });
        });
        userRoleService.saveBatch(userRoles);
        return Boolean.TRUE;
    }
}
